/**
 * 是否是邮箱
 * @param   value     字符串
 * @returns Boolean
 */
function email(value: string) {
    const reg = /^[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+)+$/;
    return !!value.match(reg);
}

/**
 * 是否是手机号
 * @param   value     手机号
 * @returns Boolean
 */
function mobile(value: string | number) {
    const val = String(value);
    const reg = /^(13[0-9]|14[01456879]|15[0-35-9]|16[2567]|17[0-8]|18[0-9]|19[0-35-9])\d{8}$/;
    return !!val.match(reg);
}

/**
 * 是否是URL
 * @param   value     字符串
 * @returns Boolean
 */
function url(value: string) {
    const reg = /http(s)?:\/\/([\w-]+\.)+[\w-]+(\/[\w-.\/?%&=]*)?/;
    return !!value.match(reg);
}

/**
 * 是否含有中文
 * @description 可以为单个汉字，或者汉字组成的字符串
 * @param   value     字符串
 * @returns Boolean
 */
function chinese(value: string) {
    const reg = /[\u4E00-\u9FA5]|[\uFE30-\uFFA0]/gi;
    return !!reg.exec(value);
}

/**
 * 是否是车牌
 * @description 蓝牌5位，绿牌6位。
 * @param   value     字符串
 * @returns Boolean
 */
function carNo(value: string) {
    const reg = /^[京沪津渝鲁冀晋蒙辽吉黑苏浙皖闽赣豫湘鄂粤桂琼川贵云藏陕甘青宁新港澳台使][A-Z][A-Z_0-9]{5,6}$/;
    return !!value.match(reg);
}

/**
 * 是否身份证号
 * @param   value       字符串或者数字
 * @returns Boolean
 */
function idCard(value: string | number) {
    value = String(value);
    const p = /^[1-9]\d{5}(18|19|20)\d{2}((0[1-9])|(1[0-2]))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]$/;
    const factor = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2];
    const parity = [1, 0, 'X', 9, 8, 7, 6, 5, 4, 3, 2];
    const code = value.substring(17);
    if (p.test(value)) {
        let sum = 0;
        for (let i = 0; i < 17; i++) {
            const id: number | string | any = value[i];
            sum += id * factor[i];
        }
        if (parity[sum % 11] == code.toUpperCase()) {
            return true;
        }
    }
    return false;
}

/**
 * 是否是日期格式
 * @description 验证一个字符串是否日期
 * @param   value       字符串，数字，日期对象
 * @returns Boolean
 */
function date(value: string | number | Date) {
    if (value == null || typeof value === 'undefined' || !value) return false;
    if (typeof value === 'string') {
        //兼容ios,mac
        value = value.replace('-', '/');
    }
    const d = new Date(value);
    return d.toString() != 'Invalid Date';
}

/**
 * 判断是否为空
 * @description 判断是否是null,对象是否为空，数组是否为空。是否为 undefaind，是否为 “”空字符串。
 * @param   value   任意
 * @returns Boolean
 */
function isEmpty(value: any) {
    if (typeof value === 'string') {
        value = value.trim();
    }
    if (value == '') return true;
    if (value == null) return true;
    if (typeof value === 'undefined') return true;
    if (Array.isArray(value)) {
        if (value.length == 0) return true;
    }
    if (typeof value === 'object') {
        if (Object.keys(value).length == 0) return true;
    }
    return false;
}

/**
 * 是否是十进制数字
 * @description 整数，小数，负数，带千分位数(2,359.08)等可以检验通过
 * @param   value     字符串或者数字
 * @returns Boolean
 */
function number(value: string | number) {
    const val = String(value);
    const reg = /^[\+-]?(\d+\.?\d*|\.\d+|\d\.\d+e\+\d+)$/;
    return !!val.match(reg);
}

/**
 * 是否是整数
 * @description 所有字符都在0-9之间，才校验通过
 * @param   value     字符串或者数字
 * @returns Boolean
 */
function digits(value: string | number) {
    const val = String(value);
    const reg = /^\d+$/;
    return !!val.match(reg);
}

/**
 * 是否是金额
 * @description 只允许最多两位小数，可以带千分位
 * @param   value     字符串或者数字
 * @returns Boolean
 */
function amount(value: string | number) {
    const val = String(value);
    const reg = /^[1-9]\d*(,\d{3})*(\.\d{1,2})?$|^0\.\d{1,2}$/;
    return !!val.match(reg);
}

/**
 * 是否是字母
 * @description 只能为"a-z"或者"A-Z"之间的字符
 * @param   value     字符串
 * @returns Boolean
 */
function letter(value: string) {
    const val = String(value);
    const reg = /^[a-zA-Z]*$/;
    return !!val.match(reg);
}

/**
 * 是否是字母或者数字
 * @description 只能是字母或者数字
 * @param   value     字符串
 * @returns Boolean
 */
function enOrNum(value: string) {
    const val = String(value);
    const reg = /^[0-9a-zA-Z]*$/g;
    return !!val.match(reg);
}

/**
 * 是否包含某个值
 * @description 字符串中是否包含某一个子字符串，区分大小写
 * @param str           字符串
 * @param subStr        子字符串
 * @returns Boolean
 */
function contains(str: string, subStr: string) {
    return str.indexOf(subStr) >= 0;
}

/**
 * 数值是否在某个范围内
 * @description 如30在"29-35"这个范围内，不在"25-28"这个范围内
 * @param value     数值
 * @param param     如"[25, 35]"
 * @returns Boolean
 */
function range(value: number, param: Array<number>) {
    return value >= param[0] && value <= param[1];
}

/**
 * 字符串长度是否在某个范围内
 * @description 如"abc"长度为3，范围在"2-5"这个区间
 * @param value     字符串
 * @param param     如"[25, 35]"
 * @returns Boolean
 */
function rangeLength(value: string, param: Array<number>) {
    return value.length >= param[0] && value.length <= param[1];
}

/**
 * 是否是json字符串
 * @description 校验是否Json字符串
 * @param   value     字符串
 * @returns Boolean
 */
function jsonString(value: string) {
    try {
        const obj = JSON.parse(value);
        return !!(typeof obj == 'object' && obj);
    } catch (e) {
        return false;
    }
}

/**
 * 是否是数组
 * @description 校验是否数组
 * @param   value     任意
 * @returns Boolean
 */
function array(value: any) {
    if (typeof Array.isArray === 'function') {
        return Array.isArray(value);
    } else {
        return Object.prototype.toString.call(value) === '[object Array]';
    }
}

/**
 * 是否是对象
 * @description 校验是否对象
 * @param   value     任意
 * @returns Boolean
 */
function object(value: any) {
    return Object.prototype.toString.call(value) === '[object Object]';
}

/**
 * 纯数字密码验证
 * @param s 字符串或者数字
 * @param len 最小长度，默认6
 * @param maxLen 最大长度，默认20
 * @returns Boolean
 */
function passwordOfNumber(s: number | string, len = 6, maxLen = 20) {
    s = String(s);
    const reg = new RegExp(`^[0-9]{${len},${maxLen}}$`);
    return !!s.match(reg);
}

/**
 * 密码验证(长度6-20)
 * @param s 字符串或者数字
 * @param model 0、包含数字和英文; 1、包含数字，英文，不允许有特殊字符; 2、包含数字和字母，可以有特殊字符。
 * @returns Boolean
 */
function passwordOfOther(s: string | number, model = 0) {
    s = String(s);
    //密码至少包含 数字和英文，长度6-20
    let reg = /^(?![0-9]+$)(?![a-zA-Z]+$)[0-9A-Za-z]{6,20}$/;
    //密码包含 数字,英文,字符中的两种以上，长度6-20
    if (model === 1) {
        reg = /^(?![0-9]+$)(?![a-z]+$)(?![A-Z]+$)(?!([^(0-9a-zA-Z)])+$).{6,20}$/;
    }

    //至少包含数字跟字母，可以有字符
    if (model === 2) {
        reg = /(?=.*([a-zA-Z].*))(?=.*[0-9].*)[a-zA-Z0-9-*/+.~!@#$%^&*()]{6,20}$/;
    }

    return !!s.match(reg);
}

/**
 * 是否是短信验证码
 * @description 短信验证码
 * @param   value     字符串
 * @param   len       验证码长度，默认为6
 * @returns Boolean
 */
function code(value: string, len = 6) {
    const reg = new RegExp(`^\\d{${len}}$`);
    return !!value.match(reg);
}

export default {
    email,
    mobile,
    url,
    chinese,
    carNo,
    idCard,
    date,
    isEmpty,
    number,
    digits,
    amount,
    letter,
    enOrNum,
    contains,
    range,
    rangeLength,
    jsonString,
    array,
    object,
    passwordOfNumber,
    passwordOfOther,
    code,
};
